package ps3838

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"strconv"
	"strings"
	"sync"
	"time"

	"lottery/conf"
	"lottery/constant"
	"lottery/models"
	"lottery/utils"

	"github.com/astaxie/beego/logs"
	"github.com/robertkrimen/otto"
	//"errors"
)

type Ps3838 struct {
	userAgent string
	agentInfo *models.Agent
	jar       *cookiejar.Jar
	client    *http.Client

	wg           *sync.WaitGroup
	stoped       chan struct{}
	gameChan     chan []*models.Game
	gameDataChan chan []*models.GameData
}

func (p *Ps3838) Platform() int {
	return constant.PS3838
}

func (p *Ps3838) AgentInfo() *models.Agent {
	return p.agentInfo
}

func (p *Ps3838) IsStop() bool {
	select {
	case <-p.stoped:
		return true
	default:
		return false
	}
}

func (p *Ps3838) errActionResp(err error) (resp *models.ActionResp) {
	resp = new(models.ActionResp)
	if err != nil {
		resp.IsSuccess = false
		resp.Msg = err.Error()
		return
	}

	resp.IsSuccess = true
	return
}

func (p *Ps3838) initLoginEnv() (err error) {
	envUrl := "http://www.ps3838.com/zh-cn/"
	_, cookies, err := utils.GetCookieWithHtml(envUrl)
	if err != nil {
		return
	}

	domain, _ := url.Parse(envUrl)
	p.jar.SetCookies(domain, cookies)
	return
}

func (p *Ps3838) Login() (actionResp *models.ActionResp) {
	p.switchIP(p.getIP())
	if err := p.initLoginEnv(); err != nil {
		return p.errActionResp(err)
	}

	// _, cookies, err := utils.GetCookieWithHtml("http://www.ps3838.com/")
	// if err != nil {
	// 	return p.errActionResp(err)
	// }

	// domain, _ := url.Parse("http://www.ps3838.com/")
	// if domain != nil {
	// 	// set cookie
	// 	p.jar.SetCookies(domain, cookies)
	// }

	// 初始化环境
	// req, err := http.NewRequest("GET", "http://www.ps3838.com/zh-cn/", nil)
	// if err != nil {
	// 	return p.errActionResp(err)
	// }
	// req.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36")
	// req.Header.Set("Referer", "http://www.ps3838.com/zh-cn/")

	// resp, err := p.client.Do(req)
	// if err != nil {
	// 	return p.errActionResp(err)
	// }
	// resp.Body.Close()

	// 登录
	params := make(url.Values)
	params.Set("loginId", p.agentInfo.LoginName)
	params.Set("password", p.agentInfo.Passwd)

	req, err := http.NewRequest("POST", "http://www.ps3838.com/member-service/v1/login?locale=zh_CN", strings.NewReader(params.Encode()))
	if err != nil {
		return p.errActionResp(err)
	}

	req.Header.Set("Referer", "http://www.ps3838.com/zh-cn/")
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Set("User-Agent", p.userAgent)

	resp, err := p.client.Do(req)
	if err != nil {
		return p.errActionResp(err)
	}

	defer resp.Body.Close()
	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return p.errActionResp(err)
	}

	if "1" != strings.TrimSpace(string(data)) {
		return p.errActionResp(fmt.Errorf("登录失败 返回:%s", string(data)))
	}

	return &models.ActionResp{IsSuccess: true}
}

func (p *Ps3838) ReLogin() *models.ActionResp {
	return p.Login()
}

type PlaceData struct {
	Stake            string  `json:"stake"`
	SelectionId      string  `json:"selectionId"`
	Odds             string  `json:"odds"`
	OddsFormat       float64 `json:"oddsFormat"`
	AcceptBetterOdds bool    `json:"acceptBetterOdds"`
	UniqueRequestId  string  `json:"uniqueRequestId"`
}

func (p *Ps3838) Place(price int, team int, tickData interface{}, gameData *models.GameData, switchIp bool) (actionResp *models.ActionResp) {

	actionResp = new(models.ActionResp)
	tick, ok := tickData.(TickResp)
	if !ok {
		logs.Warn("tick data:%+v", tick)
		actionResp.IsSuccess = false
		actionResp.Msg = "数据处理失败，无效下单"
		return
	}
	placeData := &PlaceData{}
	placeData.Stake = strconv.Itoa(price / 100 * 2)
	placeData.Odds = tick.Odds
	placeData.SelectionId = tick.SelectionID
	placeData.AcceptBetterOdds = false
	placeData.OddsFormat = 4
	placeData.UniqueRequestId = p.generateUUID()


	//fmt.Printf("palceData:%v",placeData)

	var placeData_arr []*PlaceData
	placeData_arr = make([]*PlaceData, 0, 1)
	placeData_arr = append(placeData_arr, placeData)
	send_data, err := json.Marshal(placeData_arr)
	if err != nil {
		p.errActionResp(err)
		return
	}

	//fmt.Printf("send_data:%s",send_data)

	placeUrl := fmt.Sprintf("http://www.ps3838.com/box-office/app/multiBuyV1?uniqueRequestId=%s&locale=zh_CN", p.generateUUID())

	placeReq, _ := http.NewRequest("POST", placeUrl, strings.NewReader(string(send_data)))

	placeReq.Header.Set("Referer", "http://www.ps3838.com/zh-cn/sports")
	placeReq.Header.Set("Content-Type", "application/json")
	placeReq.Header.Set("User-Agent", p.userAgent)
	placeResp, err := p.client.Do(placeReq)
	if err != nil {
		return p.errActionResp(err)
	}

	defer placeResp.Body.Close()
	data, err := ioutil.ReadAll(placeResp.Body)
	if err != nil {
		return p.errActionResp(err)
	}

	var placeResp_data []PlaceResp

	err = json.Unmarshal(data,&placeResp_data)
	logs.Notice("PS下注数据:%v",string(data))
	if(err !=nil){
		actionResp.IsSuccess = false
		actionResp.Msg = "下注返回数据处理失败,下注数据:"+string(data)
		return
	}
	if(len(placeResp_data)<=0){
		actionResp.IsSuccess = false
		actionResp.Msg = "下注返回数据处理失败,下注数据:"+string(data)
		return
	}


	if(placeResp_data[0].Status=="ERROR"){
	actionResp.IsSuccess = false
	actionResp.Msg = "下注失败,失败信息:"+placeResp_data[0].ErrorCode
	return
	}
	if(placeResp_data[0].Status == "PENDING_ACCEPTANCE"){
		logs.Notice("PS下注成功，但是风险下注，有可能被撤单！")
		actionResp.IsSuccess = true
		actionResp.Msg = "PS下注成功，但是风险下注，有可能被撤单！"
		return
	}
	if(placeResp_data[0].Status == "ACCEPTED"){
		logs.Notice("PS下注成功,已经接受")
		actionResp.IsSuccess = true
		actionResp.Msg = "PS下注成功！"
		return
	}
	return
}

func (p *Ps3838) CheckLogin() (actionResp *models.ActionResp) {
	actionResp = new(models.ActionResp)
	reqUrl := "http://www.ps3838.com/member-service/v1/account-balance?locale=zh_CN"
	params := make(url.Values)
	params.Set("json", "")
	req, err := http.NewRequest("POST", reqUrl, strings.NewReader(params.Encode()))
	if err != nil {
		return p.errActionResp(err)
	}
	req.Header = p.getDefaultHeader()
	resp, err := p.client.Do(req)
	if err != nil {
		return p.errActionResp(err)
	}

	defer resp.Body.Close()
	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return p.errActionResp(err)
	}
	balanceResp := new(BalanceResp)
	if err = json.Unmarshal(data, balanceResp); err != nil {
		return p.errActionResp(err)
	}
	if !balanceResp.Success {
		return p.errActionResp(fmt.Errorf("已登出"))
	}
	p.agentInfo.Balance = int(balanceResp.BetCredit * 100)
	return &models.ActionResp{IsSuccess: true}
}

func (p *Ps3838) generateUUID() (str string) {

	js := `var generateUUID = function() {
    function a() {
        return Math.floor((1 + Math.random()) * 65536).toString(16).substring(1)
    }
    return a() + a() + "-" + a() + "-" + a() + "-" + a() + "-" + a() + a() + a()
	};
	 uid = generateUUID()`
	vm, _, err := otto.Run(js)
	if err != nil {

		return
	}
	str_tmp, err := vm.Get("uid")
	str = str_tmp.String()
	//fmt.Println("uid",str_tmp.String(),err)
	return
}

func (p *Ps3838) Run() {
	p.wg.Add(1)
	defer p.wg.Done()
	flushTime := time.Duration(conf.LoadResource().PS3838Refresh) * time.Millisecond

	tick := time.NewTicker(flushTime)
	for {
		select {
		case _ = <-tick.C:
			start := utils.CurrentMills()
			games, gameDatas, err := p.getGameData()
			if err != nil {
				logs.Warn("crawl games %s", err.Error())
				continue
			}

			logs.Debug("ps3838 getGameData use time:%d mill sec", utils.CurrentMills()-start)
			p.gameChan <- games
			p.gameDataChan <- gameDatas
		case _ = <-p.stoped:
			close(p.gameChan)
			close(p.gameDataChan)
			return
		}
	}
}

type TickData struct {
	SelectionID string `json:"selectionId"` // "438135736|778469463|0|2|1|0|0.25|1"  下注ID|比赛ID|全场0,半场1|让球2，大小盘3|0|盘口|主场或大盘0，否则1
	OddsFormat  int    `json:"oddsFormat"`  // 1
	OddsID      string `json:"oddsId"`      // 比赛ID|全场0,半场1|让球2，大小盘3|0|盘口|主场或大盘0，否则1
}

func (p *Ps3838) Tick(team int, gameData *models.GameData) (rate float64, tickData interface{}, discard bool, err error) {
	tick := &TickData{}

	orderId := gameData.HandicapId
	gameId := gameData.Game.PlatformGameId
	var play, handicapType, over, size int //size 主场 0 客场 1  大盘 3 小盘 4
	//fmt.Printf("gameData:%v   handicap:%f",gameData,gameData.Handicap)
	var handicap float64 = gameData.Handicap
	if team == 1 {
		over = 0
	} else {
		over = 1
	}

	switch gameData.HandicapType {
	case 1:
		size = 0
		play = 0
		handicapType = 2
		if team == 2 {
			// 反盘
			handicap = -handicap
		}
	case 2:
		size = 1
		play = 0
		handicapType = 2
	case 3:
		size = 3
		play = 1
		handicapType = 3
		if team == 2 {
			// 反盘
			handicap = -handicap
		}
	case 4:
		size = 4
		play = 1
		handicapType = 3
	}
	tick.SelectionID = fmt.Sprintf("%s|%s|%d|%d|%d|%s|%.2f|%d", orderId, gameId, play, handicapType, size, gameData.ExtData,handicap, over)
	tick.OddsID = fmt.Sprintf("%s|%d|%d|%d|%s|%.2f|%d", gameId, play, handicapType, size,gameData.ExtData ,handicap, over)
	tick.OddsFormat = 4

	ticks := make([]*TickData, 0, 1)
	ticks = append(ticks, tick)
	selectionData, err := json.Marshal(ticks)
	if err != nil {
		p.errActionResp(err)
		return
	}
	//selectionData = strings.NewReader(string(selectionData))
	reqUrl := fmt.Sprintf("http://www.ps3838.com/member-service/v1/multiTicket?selectionData=%s&_=%d&locale=zh_CN", url.QueryEscape(string(selectionData)), utils.CurrentMills())
	//fmt.Println("reqUrl:",reqUrl)

	req, _ := http.NewRequest("GET", reqUrl, nil)
	header := make(http.Header)
	header.Set("Referer", "http://www.ps3838.com/zh-cn/sports")
	header.Set("User-Agent", p.userAgent)
	req.Header = header
	resp, err := p.client.Do(req)
	if err != nil {
		logs.Warn("ps3838 client do order req err %s", err.Error())

		return
	}

	defer resp.Body.Close()
	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return
	}


	var tickResp []TickResp

	//fmt.Printf("tickResp:%s",string(data))
	err  = json.Unmarshal(data,&tickResp)

	if(err !=nil){
		return
	}

	tickData = tickResp[0]

	rate ,err= strconv.ParseFloat(tickResp[0].Odds,64)

	//fmt.Printf("tickResp:%s",string(data))
	//fmt.Printf("tickData:odds:%s",tickResp[0].Odds)
	//fmt.Printf("tickResult:%v rate:%f",tickResp,rate)
	////panic("------------------stop---------------------")
	if(err !=nil){
		return
	}

	return
}

func (p *Ps3838) GetGames() <-chan []*models.Game {
	return p.gameChan
}

func (p *Ps3838) GetGameData() <-chan []*models.GameData {
	return p.gameDataChan
}

func (p *Ps3838) GetOrderInfo(t time.Time) (html string, err error) {

	reqUrl :="http://www.ps3838.com/zh-cn/account/my-bets-full"

	req,err :=http.NewRequest("GET",reqUrl,nil)
	if(err !=nil){
		return
	}
	req.Header.Set("Referer","http://www.ps3838.com/zh-cn/sports")
	req.Header.Set("User-Agent",p.userAgent)

	resp,err :=p.client.Do(req)
	if(err !=nil){
		return
	}

	defer resp.Body.Close()

	data,err :=ioutil.ReadAll(resp.Body)

	if(err !=nil){
		return
	}
	fmt.Println("PS下注记录:",string(data))
	logs.Notice("PS下注记录长度：%s",len(string(data)))
	html = string(data)
	return
}

func (p *Ps3838) Destroy() {
	logs.Warn("ps3838 destroy ...%d", p.agentInfo.Id)
	close(p.stoped)
	p.wg.Wait()
}

func (p *Ps3838) getDefaultHeader() http.Header {
	header := make(http.Header)
	header.Set("User-Agent", p.userAgent)
	return header
}
func (p *Ps3838) switchIP(ip string) {
	if ip == "" {
		return
	}
	p.client.Transport = utils.GetTransport(ip, "")
}
func (p *Ps3838) getIP() string {
	if IPsRing == nil {
		return ""
	}
	return IPsRing.GetIp()
}